package com.trayicon.messagenotifier.main;

import java.awt.Button;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JWindow;

import com.trayicon.messagenotifier.enums.ConfigEvent;


public class NotifyFrame extends JWindow {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private MyCanvas canvas;
	private NotifyFrame THIS;
	
	/**
	 * Default constructor
	 */
	public NotifyFrame() {
		super();
		THIS = this;
		int width = 450;
		int height = 45;
		setLayout(null);
	    setSize(width, height);
	    setAlwaysOnTop(true);
	    
	    setOpacity(0.5f);
		getContentPane().setBackground(Color.WHITE);
	    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
        Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
        int x = (int) rect.getMaxX() - getWidth();
        int y = (int) rect.getMaxY() - getHeight();
        setLocation(x, y);
        
        canvas = new MyCanvas();
        add(canvas);
        canvas.setLocation(0, 0);
        canvas.setSize(width-18, height);
        
        Button btnDeleteCurrent = new Button("x");
        add(btnDeleteCurrent);
        btnDeleteCurrent.setLocation(width - 16, 2);
        btnDeleteCurrent.setSize(16, 22);
        btnDeleteCurrent.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				CustomDictionary.GET().deleteWord(canvas.word.getWord());
				canvas.setWord(new Word("locnv - locnv@gmail.com - 01683508402", "", ""));
				canvas.repaint();
			}
		});
        
        canvas.addMouseListener(new AbstractMouseListener() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (THIS.isVisible()) {
					THIS.setVisible(false);
				}
			}
		});
        
        ChangeOpacyListener l = new ChangeOpacyListener(THIS);
        canvas.addMouseListener(l);
        addMouseListener(l);
        btnDeleteCurrent.addMouseListener(l);
	}
	
	public void registryConfigChangeListener(ConfigFrame configManager) {
		configManager.addConfigChangeListener(canvas);
	}
	
	
	public void setWord(Word word) {
		canvas.setWord(word);
	}
	
	private boolean isAutoScroll = true;
	@Override
	public void setVisible(boolean isVisible) {
		super.setVisible(isVisible);
		
		if (isAutoScroll) {
			canvas.updatePaintTask(isVisible);
		}
	}
	
	@SuppressWarnings("serial")
	class MyCanvas extends Canvas implements IConfigChangeListener {
		private Word word;
		private Font fontWord = null;
		//private Font fontDescription = null;
		
		private int xLeft = 10;
		private int textWidth = 0;
		float lastOpacity = 0.5f;
		private Timer timer = null;
		private RepaintTimerTask repainTask = null;
		
		private boolean isDrawnImage;
		
		public MyCanvas() {
			super();
			fontWord = new Font("Verdana", Font.BOLD, 20);
			//fontDescription = new Font("Verdana", Font.ITALIC, 18);
			isDrawnImage = true;
		}
		
		private int bufferWidth;
	    private int bufferHeight;
	    private Image bufferImage;
	    private Graphics bufferGraphics;
	    
	    private Image image = null;
		
		@Override
		public void paint(Graphics g) {
			//	Checks the buffersize with the current panelsize
	        //  or initialises the image with the first paint
	        if(bufferWidth != getSize().width || bufferHeight != getSize().height || 
	        		bufferImage == null || bufferGraphics == null) {
	        	resetBuffer();
	        }
	        
			if (bufferGraphics != null) {
				bufferGraphics.clearRect(0, 0, bufferWidth, bufferHeight);
				paintBuffer(bufferGraphics);
				g.drawImage(bufferImage, 0, 0, this);
			}
		}
		
		private boolean isPaintBgrGradient = false;
		private Color bgrColor = Color.WHITE;
		private void paintBuffer(Graphics g) {
			// fill gradient background
			Graphics2D g2 = (Graphics2D) g;
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);
			g.setColor(bgrColor);
			g.fillRect(0, 0, getWidth(), getHeight());
			if (isPaintBgrGradient) {
				int width = getWidth();
				int height = getHeight();
				Paint gradient = new GradientPaint(0, 0, Color.WHITE, width, height, Color.DARK_GRAY);
				g2.setPaint(gradient);
				g2.fillRect(0, 0, width, height);
			}
			//xLeft = getWidth()- g2.getFontMetrics(fontWord).stringWidth(word.getWord())-15;
			g2.setFont(fontWord);
			g2.setColor(Color.BLUE);
			g2.drawString(word.getWord(), xLeft, 30);
			
			if (isDrawnImage && !word.getImagePath().isEmpty()) {
				drawImage(g2);
			}
		}
		
		private void resetBuffer() {
			// always keep track of the image size
			bufferWidth = getSize().width;
			bufferHeight = getSize().height;

			// clean up the previous image
			if (bufferGraphics != null) {
				bufferGraphics.dispose();
				bufferGraphics = null;
			}
			if (bufferImage != null) {
				bufferImage.flush();
				bufferImage = null;
			}
			System.gc();

			// create the new image with the size of the panel
			bufferImage = createImage(bufferWidth, bufferHeight);
			bufferGraphics = bufferImage.getGraphics();
			
			calculateDisplayPosition();
		}

		private void drawImage(Graphics g) {
			if (image == null) {
				return;
			}
			g.setColor(bgrColor);
			g.fillRect(0, 0, imageWidth+6, imageWidth+6);
			g.drawImage(image, 3, 3, imageWidth, imageWidth, this);
		}
		
		private int imageWidth = 42;
		private void calculateDisplayPosition() {
			if (bufferGraphics != null) {
				textWidth = bufferGraphics.getFontMetrics(fontWord).stringWidth(word.getWord());
				xLeft = getWidth()- textWidth;
				isPause = true;
				pauseCountDown = 20;
				if (hasImage() && xLeft < imageWidth+5) {
					xLeft = imageWidth + 5;
				} else if (xLeft < 0){
					xLeft = 5;
				} else {
					isPause = false;
				}
			}
		}
		public void setWord(Word word) {
			this.word = word;
			calculateDisplayPosition();
			
			if (!word.getImagePath().isEmpty()) {
				if (word.getImagePath().startsWith("http")) {
					try {
						URL url = new URL(word.getImagePath());
						image = ImageIO.read(url);
					} catch (MalformedURLException e) {
						System.err.println("Error while loading image from url: " +e.getMessage());
					} catch (IOException e) {
						System.err.println("Error while loading image from url: " +e.getMessage());
					}
				} else {
					image = new ImageIcon(word.getImagePath()).getImage();
				}
			}
			
			repaint();
		}
		
		private boolean isPause = false;
		private boolean isPauseAtEnd = false;
		private int pauseCountDown = 20;
		private int pauseCountDownDefault = 20;
		public void update() {
			if (textWidth < getWidth()) {
				return;
			}
			
			if (isPause) {
				pauseCountDown --;
				if (pauseCountDown == 0 && isPauseAtEnd) {
					isPauseAtEnd = false;
					pauseCountDown = pauseCountDownDefault;
					
					// reset
					xLeft = 5;
					if (hasImage()) {
						xLeft += imageWidth;
					}
					repaint();
				}
				
				if (pauseCountDown == 0) {
					isPause = false;
				}
			} else {
				if (xLeft + textWidth < getWidth()-150) {
						isPause = true;
						isPauseAtEnd = true;
						pauseCountDown = pauseCountDownDefault;
				} else {
					xLeft -= 3;
				}
				repaint();
			}
			
		}
		
		public void updatePaintTask(boolean isVisible) {
			if (isVisible) {
				if (repainTask != null) {
					return;
				}
				
				if (timer == null) {
					timer = new Timer();
				}
				repainTask = new RepaintTimerTask(this);
				timer.schedule(repainTask, 2000, 120);
			} else {
				if (timer != null) {
					timer.cancel();
				}
				if (repainTask != null) {
					repainTask.cancel();
				}
				repainTask = null;
				timer = null;
			}
		}
		
		private boolean hasImage() {
			if (isDrawnImage && word.getImagePath()!=null && !word.getImagePath().isEmpty()) {
				return true;
			}
			
			return false;
		}

		@Override
		public void configChange(ConfigEvent configEvent, Object value) {
			if (configEvent == ConfigEvent.ENABLE_DISPLAY_IMAGE) {
				isDrawnImage = true;
			} else if (configEvent == ConfigEvent.DISABLE_DISPLAY_IMAGE) {
				isDrawnImage = false;
			} else if (configEvent == ConfigEvent.OPACITY_CHANGED) {
				int intValue = Integer.parseInt(value.toString());
				lastOpacity = (float)intValue / 100.0f;
				setOpacity(lastOpacity);
			}
			repaint();
		}
	}
	
	class ChangeOpacyListener implements MouseListener {
		private NotifyFrame parent;
		public ChangeOpacyListener(NotifyFrame parent) {
			this.parent = parent;
		}

		@Override
		public void mouseReleased(MouseEvent e) {}
		@Override
		public void mousePressed(MouseEvent e) {}
		public void mouseExited(MouseEvent e) {
			parent.setOpacity(parent.getLastOpacity());
		}
		@Override
		public void mouseEntered(MouseEvent e) {
			parent.setOpacity(1.0f);
		}
		public void mouseClicked(MouseEvent e) {}
		
	}

	public void setAlwaysOnTop1(boolean alwayOnTop) {
		setAlwaysOnTop(alwayOnTop);
		canvas.repaint();
	}

	public float getLastOpacity() {
		return canvas.lastOpacity;
	}
	
	class RepaintTimerTask extends TimerTask {
		private MyCanvas canvas;
		
		public RepaintTimerTask(MyCanvas canvas) {
			this.canvas = canvas;
		}
		@Override
		public void run() {
			canvas.update();
		}
	}
}
